package com.example.d8_stream;

import java.util.*;
import java.util.stream.Stream;

/**
 * Stream流提供的中间方法
 */
/*
Stream提供的常用中间方法                                      说明
Stream<T> filter(Predicate<?super T> predicate)            用于对流中的数据进行过滤
Stream<T> sorted()                                         对元素进行升序排序
Stream<T> sorted(Comparator<? super T> comparator          按照指定规则排序
Stream<T> limit(long maxSize)                              获取前几个元素
Stream<T> skip(long n)                                     跳过前几个元素
Stream<T> distinct()                                       去除流中重复的元素
<R> Stream<R> map(Function<? super T,? extends R> mapper)  对元素进行加工,并返回对应的新流
static <T> Stream<T> concat(Stream a, Stream b)            合并a和b两个流为一个流
 */
public class StreamTest3 {
    public static void main(String[] args) {
        List<Double> scores = new ArrayList<>();
        Collections.addAll(scores, 88.5, 100.0, 60.0, 99.0, 9.5, 99.6, 25.0);
        // 需求1：找出成绩大于等于60分的数据,并升序后,再输出
        // 先获取到了stream流在通过filter过滤后,再通过sorted排序 sorted这个方法可以new 一个匿名内部类如果需要降序排序可以自己指定规则 最后通过forEach输出
        // scores.stream().filter(s -> s >= 60.0).sorted().forEach(s -> System.out.println(s));
        // 使用方法引用简化
        scores.stream().filter(s -> s >= 60.0).sorted().forEach(System.out::println);


        List<Student> students = new ArrayList<>();
        Student s1 = new Student("蜘蛛精", 26, 172.5);
        Student s2 = new Student("蜘蛛精", 26, 172.5);
        Student s3 = new Student("紫霞", 23, 167.6);
        Student s4 = new Student("白晶晶", 25, 169.0);
        Student s5 = new Student("牛魔王", 35, 183.3);
        Student s6 = new Student("牛夫人", 34, 168.5);
        Collections.addAll(students, s1, s2, s3, s4, s5, s6);
        // 需求2：找出年龄大于等于23,且年龄小于等于30岁的学生,并按照年龄降序输出.
        // 先获取到stream流在使用filter过滤后,再通过sorted排序 sorted这个方法可以new 一个匿名内部类如果需要降序排序可以自己指定规则 最后通过forEach输出
//        students.stream().filter(s -> s.getAge() >= 23 && s.getAge() <= 30).sorted(new Comparator<Student>() {
//            @Override
//            public int compare(Student o1, Student o2) {
//                return o2.getAge() - o1.getAge();
//            }
//        }).forEach(s -> System.out.println(s));
        // 在定义比较规则的时候用lambda化简
        students.stream().filter(s -> s.getAge() >= 23 && s.getAge() <= 30)
                .sorted((o1, o2) -> o2.getAge() - o1.getAge()).forEach(System.out::println);


        // 需求3：取出身高最高的前3名学生,并输出
        // 先获取到stream流在使用sorted排序需要按照身高进行降序排序 但是身高是double类型的二sorted方法里面的比较器返回值是int类型的
        // 所有需要使用Double.compare()方法进行比较
        // 没有用Lambda简化的写法
//        students.stream().sorted(new Comparator<Student>() {
//            @Override
//            public int compare(Student o1, Student o2) {
//                return Double.compare(o2.getHeight(), o1.getHeight());
//            }
//        }).limit(3).forEach(s -> System.out.println(s));
        // lambda简化之后的写法
//        students.stream().sorted((o1, o2) -> Double.compare(o2.getHeight(), o1.getHeight()))
//                .limit(3).forEach(s -> System.out.println(s));
        // System.out.println 可以用方法引用化简
        students.stream().sorted((o1, o2) -> Double.compare(o2.getHeight(), o1.getHeight()))
                .limit(3).forEach(System.out::println);
        System.out.println("---------------------------------------------------------------------");


        // 需求4：取出身高倒数的2名学生,并输出  s1 s2 s3 s4 s5 s6
        // 第一种方法 按照升高升序排序 那么第一个和第二个就是最矮的 取出第一个和第二个即可
        students.stream().sorted((o1, o2) -> Double.compare(o1.getAge(), o2.getAge())).limit(2).forEach(System.out::println);
        // 第二方法 按照升高降序排序 跳过前四个后面的两个就是最矮的
        students.stream().sorted(((o1, o2) -> Double.compare(o2.getHeight(), o1.getHeight()))).skip(students.size() - 2).forEach(System.out::println);
        System.out.println("---------------------------------------------------------------------");


        // 需求5：找出身高超过168的学生叫什么名字,要求去除重复的名字,再输出
        // 原始的写法
//        students.stream().filter(new Predicate<Student>() {
//            @Override
//            public boolean test(Student student) {
//                return student.getHeight() > 168;
//            }
//        }).map(new Function<Student, Object>() {
//            @Override
//            public Object apply(Student student) {
//                return student.getName();
//            }
//        }).distinct().forEach(s -> System.out.println(s));
        // Lambda表达式简化
//        students.stream().filter(s -> s.getHeight() > 168).map(s -> s.getName())
//                .distinct().forEach(s -> System.out.println(s));
        // 可以使用方法引用化简
        /**
         * 流处理学生列表,筛选出身高超过168厘米的学生,并打印他们的名字。
         * 这里使用了Java 8的流式处理,通过filter方法筛选学生,map方法提取名字,
         * distinct方法去重,最后通过forEach方法打印每个学生的唯一名字。
         * 这种流式处理方式使得代码更加简洁,并且易于理解,同时也充分利用了Java 8的特性。
         */
        students.stream() // 将学生列表转换为流
                .filter(s -> s.getHeight() > 168) // 筛选出身高超过168厘米的学生
                .map(Student::getName) // map方法将学生对象映射为学生姓名 提取每个学生的姓名并返回 Student::getName表示student.getName()
                .distinct() // （去重）确保结果中的姓名是唯一的
                .forEach(System.out::println); // 打印每个学生的姓名
        System.out.println("---------------------------------------------------------------------");

        // 如果希望distinct去重复,自定义类型的对象（希望内容一样就认为重复,重写hashCode,equals）
        students.stream().filter(s -> s.getHeight() > 168).distinct().forEach(System.out::println);


        System.out.println("---------------------------------------------------------------------");
        Stream<String> st1 = Stream.of("张三", "李四");
        Stream<String> st2 = Stream.of("张三2", "李四2", "王五2");
        // 注意如果合并的两个流的类型不一样 合并之后的流泛型需要是Object
        Stream<String> allStream = Stream.concat(st1, st2);
        allStream.forEach(System.out::println);
    }
}
